package cshi.thread.FutureImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public abstract class AbstractListenableFuture<T,L extends GenericCompletionListener>
	implements ListenableFuture<T, L>{
	private final ExecutorService service;
	private List<GenericCompletionListener<? extends Future<T>>> listeners;
	
	protected AbstractListenableFuture(ExecutorService executorService) {
		service = executorService;
		listeners = new ArrayList<GenericCompletionListener<? extends Future<T>>>();
	}
	
	protected ExecutorService executor() {
		return service;
	}
	protected Future<T> addToListeners(final GenericCompletionListener listener) {
		if (listener == null)
			throw new IllegalArgumentException("The listener can't be null");
		synchronized (this) {
			listeners.add(listener);
		}
		if (isDone())
			notifyListeners();
		return this;
	}
	protected void notifyListener(final ExecutorService es,
			final Future<?> future,final GenericCompletionListener listener) {
		es.submit(new Runnable() {
			
			@Override
			public void run() {
				try {
					listener.onComplete(future);
				} catch (Throwable t) {
					t.printStackTrace();
				}
				
				
			}
		});
	}
	protected void notifyListeners() {
		notifyListeners(this);
	}
	protected void notifyListeners(final Future<?> future) {
		final List<GenericCompletionListener> copy = 
				new ArrayList<GenericCompletionListener>();
		synchronized (this) {
			copy.addAll(listeners);
			listeners = new ArrayList<GenericCompletionListener<? extends Future<T>>>();
		}
		for (GenericCompletionListener<? extends Future<? super T>> listener:copy){
			notifyListener(executor(), future, listener);
		}
	}
	
	protected Future<T> removeFromListeners(GenericCompletionListener<? extends Future<T>> listener) {
		if (listener == null)
			throw new IllegalArgumentException("the listener can't be null.");
		if (!isDone()) {
			synchronized (this) {
				listeners.remove(listener);
			}
		}
		return this;
	}
	
}
